/**
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 3
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 * Author(s): Bikov Rinat <becase@altlinux.org>
 */
 
#include <QtGui>
#include <QColor>
#include "ScanTest.h"
//
ScanTest::ScanTest( QWidget * parent, Qt::WFlags f) 
	: QMainWindow(parent, f)
{
	setupUi(this);
	imageLabel = new QLabel;
	imageLabel->setBackgroundRole(QPalette::Base);
	imageLabel->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
	imageLabel->setScaledContents(true);
	image = NULL;
	settings = new QSettings("ScanTest", "ScanTest", this);
	readSettings();
	scrollArea->setBackgroundRole(QPalette::Dark);
	scrollArea->setWidget(imageLabel);
	assignActions();
}
//

void ScanTest::fitToWindow(bool f){
	if (image != NULL){
		scrollArea->setWidgetResizable(f);
		imageLabel->adjustSize();
	}
}
void ScanTest::closeEvent(QCloseEvent *event){
	writeSettings();
	event->accept();
}

void ScanTest::openDirectory(){
	open = new QFileDialog(this);
	open->setAcceptMode(QFileDialog::AcceptOpen);
	open->setFileMode(QFileDialog::Directory);
	if (directory.isEmpty()){
		directory = QDir::currentPath();
	}
	open->setDirectory(directory);
	open->show();
	connect(open, SIGNAL(fileSelected(const QString &)), 
			this, SLOT(directoryOpened(const QString &)));
	
}

void ScanTest::assignActions(){
	actionOpen->setShortcut(tr("Ctrl+O"));
	actionOpen->setStatusTip(tr("Open the directory"));
	connect(actionOpen, SIGNAL(triggered()), this, SLOT(openDirectory()));
	
	actionNext->setShortcut(tr("Ctrl+N"));
	actionNext->setStatusTip(tr("Open next file image"));
	connect(actionNext, SIGNAL(triggered()), this, SLOT(openNextFile()));
	
	actionFit->setShortcut(tr("Ctrl+F"));
	actionFit->setStatusTip(tr("Fit image to window"));
	connect(actionFit, SIGNAL(toggled(bool)), this, SLOT(fitToWindow(bool)));
}

void ScanTest::directoryOpened(const QString &s){
	if (s != directory){
		directory = s;
		settings->setValue("directory", s);
	}
	fileList.clear();
	labelDirectory->setText(s);
	dir = new QDir(s);
	QFileInfoList list = dir->entryInfoList(QDir::Files);
	while (!list.isEmpty()){
		fileList.append(list.first().absoluteFilePath());
		list.pop_front();
	}
	openNextFile();
}

void ScanTest::openNextFile(){
	if (image == NULL){
		image = new QImage;
	}	
	bool loaded = false;
	while(!fileList.empty() && !loaded){
		if (!loaded){
			QApplication::setOverrideCursor(Qt::WaitCursor);
			loaded = image->load(fileList.first());
			if (loaded){
				bits = image->bits();
				bytesCount = image->bytesPerLine();
				labelDirectory->setText(fileList.first());
				treatImage();
			}
		}
		fileList.pop_front();
	}
	QApplication::restoreOverrideCursor();
}

void ScanTest::bfs(){
	unsigned int MAX = image->height() * image->width() * 4;
	Point *a = new Point[MAX];
	unsigned int begin, end;
	begin = 0;
	end = 0;
	Point p, np;	
	//const QRgb white = 0xFFFFFFFF;
	//const QRgb green = 0xFFFF0000;
	//const QRgb black = 0xFF000000;
	int step[][2] = {{0, 1}, {0, -1}, {1, 0},{-1, 0}};
	int nx = image->width();
	int ny = image->height();
	int x, y;
	for (y = 0; y < ny && !end; y++){
		for (x = 0; x < nx && !end; x++){
			if (!isBit(x, y)){
				setBit(x, y, true);
				a[end].x = x;
				a[end++].y = y;
			}
		}
	}
	QRect rect = image->rect();
	while (begin != end){
		p = a[begin++];
		if (begin >= MAX){
			begin -= MAX;
		}
		for (int i = 0; i < 4; i++){
			np = p;
			np.x += step[i][0];
			np.y += step[i][1];
			if (np.x >= 0 && np.x < nx && np.y >= 0 && np.y < ny && !isBit(np)){
				setBit(np, true);
				a[end++] = np;
				if (end >= MAX){
					end -= MAX;
				}
			}
		}
	}
	delete []a;
}

void ScanTest::convexHull(){
	const int nx = image->width();
	const int ny = image->height();
	const int MAX = nx * ny * 2 + 1;
	Point * a = new Point[MAX];
	int na = 0;
	int x, y;
	int i;
	for (x = 0; x < nx; x++){
		for (y = 0; y < ny; y++){
			if (isBit(x, y)){
				if (!na){
					a[na].x = x;
					a[na++].y = y;
					//fprintf(stderr, "First point: (%d,%d)\n", x, y);
				}else{
					while(na >= 2 && (a[na-1].x - a[na-2].x)*(y - a[na-1].y) - 
								(a[na-1].y - a[na-2].y)*(x - a[na-1].x) <= 0){
						na--;
					}
					a[na].x = x;
					a[na++].y = y;
					//fprintf(stderr, "(%d,%d) ", x, y);
				}
				break;
			}
		}
	}
	//for (i = 0; i < na; i++){
		//setBall(a[i], 3);
		//line(a[i], a[(i+1)%na]);
	//}
	for (y = a[na-1].y + 1; y < ny; y++){
		for (x = nx - 1; x >= 0; x--){
			if (isBit(x, y)){
				while(na >= 2 && (a[na-1].x - a[na-2].x)*(y - a[na-1].y) - 
							(a[na-1].y - a[na-2].y)*(x - a[na-1].x) <= 0){
					na--;
				}
				//fprintf(stderr, "(%d,%d) ", x, y);
				a[na].x = x;
				a[na++].y = y;
				break;
			}
		}
	}
	for (x = a[na-1].x - 1; x >= a[0].x; x--){
		for (y = ny - 1; y >= 0; y--){
			if (isBit(x, y)){
				while(na >= 2 && (a[na-1].x - a[na-2].x)*(y - a[na-1].y) - 
							(a[na-1].y - a[na-2].y)*(x - a[na-1].x) <= 0){
					na--;
				}
				a[na].x = x;
				a[na++].y = y;
				//fprintf(stderr, "(%d,%d) ", x, y);
				break;
			}
		}
	}
	for (y = a[na-1].y - 1; y >= a[0].y; y--){
		for (x = 0; x < nx; x++){
			if (isBit(x, y)){
				while(na >= 2 && (a[na-1].x - a[na-2].x)*(y - a[na-1].y) - 
							(a[na-1].y - a[na-2].y)*(x - a[na-1].x) <= 0){
					na--;
				}
				a[na].x = x;
				a[na++].y = y;
				//fprintf(stderr, "(%d,%d) ", x, y);
				break;
			}
		}
	}
	na--;
	a[na] = a[0];
	fprintf(stderr, "Points count: %d\n", na);
	for (i = 0; i < na; i++){
		setBall(a[i], 3);
		line(a[i], a[i+1]);
		fprintf(stderr, "(%d,%d) ", a[i].x, a[i].y);
	}
	fprintf(stderr, "\n");
	delete [] a;
}

void ScanTest::line(const Point &a, const Point &b){
	// current values of coordinates
	int x, y;
	// +1 or -1 value to change of x iterator value
	int xi = (a.x < b.x)?1:-1;
	// +1 or -1 value to change of y iterator value
	int yi = (a.y < b.y)?1:-1;
	setBit(a, true);
	setBit(b, true);
	for (x = a.x; x != b.x; x += xi){
		y = a.y + ((x - a.x)*(b.y - a.y))/(b.x - a.x);
		setBit(x, y, true);
	}
	for (y = a.y; y != b.y; y+= yi){
		x = a.x + ((y - a.y)*(b.x - a.x))/(b.y - a.y);
		setBit(x, y, true);
	}
}

void ScanTest::treatImage(){
	if (image == NULL){
		QMessageBox::warning(this, "ScanTreat", "Cannot treat the image:"
					" null pointer", QMessageBox::Ok);
		return;
	}
	QString txt("Size: ");
	txt.append(QString("height: %1 ").arg(QString::number(image->height())));
	txt.append(QString("width: %1\n").arg(QString::number(image->width())));	
	outputText->setPlainText(txt);
	convexHull();
	imageLabel->setPixmap(QPixmap::fromImage(*image));
	scrollArea->setWidgetResizable(actionFit->isChecked());
	imageLabel->adjustSize();
}


void ScanTest::readSettings(){
	restoreGeometry(settings->value("geometry").toByteArray());
	directory = settings->value("directory").toString();
	fileList = settings->value("files").toStringList();
	
}

void ScanTest::writeSettings(){
	settings->setValue("geometry", saveGeometry());
	settings->setValue("directory", directory);
	settings->setValue("files", fileList);
}
